#
# This plugin provides an msf daemon interface that spawns a listener on a
# defined port (default 55552) and gives each connecting client its own
# console interface.  These consoles all share the same framework instance.
# Be aware that the console instance that spawns on the port is entirely
# unauthenticated, so realize that you have been warned.
#

require "msf/core/rpc/v10/service"
require "fileutils"

module Msf

###
#
# This class implements the msfd plugin interface.
#
###
class Plugin::MSGRPC < Msf::Plugin

  #
  # The default local hostname that the server listens on.
  #
  DefaultHost ||= "127.0.0.1"

  #
  # The default local port that the server listens on.
  #
  DefaultPort ||= 55552

  #
  # ServerPort
  #
  # 	The local port to listen on for connections.  The default is 55553
  #
  def initialize(framework, opts)
    super

    host = opts['ServerHost'] || DefaultHost
    port = opts['ServerPort'] || DefaultPort
    ssl  = (opts['SSL'] && opts['SSL'].to_s =~ /^[ty]/i) ? true : false
    cert = opts['SSLCert']

    user = opts['User'] || "msf"
    pass = opts['Pass'] || ::Rex::Text.rand_text_alphanumeric(8)
    uri  = opts['URI'] || "/api"
    timeout = opts['TokenTimeout'] || 300

    print_status("MSGRPC Service:  #{host}:#{port} #{ssl ? " (SSL)" : ""}")
    print_status("MSGRPC Username: #{user}")
    print_status("MSGRPC Password: #{pass}")

    self.server	= ::Msf::RPC::Service.new(framework, {
      :host   => host,
      :port   => port,
      :ssl    => ssl,
      :cert   => cert,
      :uri    => uri,
      :tokens => { },
      :token_timeout => timeout
    })

    self.server.add_user(user, pass)

    # If the run in foreground flag is not specified, then go ahead and fire
    # it off in a worker thread.
    unless opts['RunInForeground'] == true
      # Store a handle to the thread so we can kill it during
      # cleanup when we get unloaded.
      self.thread = Thread.new { run }
      framework.threads.register(self.thread, "MetasploitRPCServer", true)
    end
  end

  #
  # Returns 'msgrpc'
  #
  def name
    "msgrpc"
  end

  #
  # Returns the plugin description.
  #
  def desc
    "Provides a MessagePack interface over HTTP"
  end

  #
  # The meat of the plugin, sets up handlers for requests
  #
  def run
    # Start the actual service
    self.server.start

    # Register
    framework.threads.register(Thread.current, "MetasploitRPCServer", true)

    # Wait for the service to complete
    self.server.wait
  end

  #
  # Closes the listener service.
  #
  def cleanup
    self.server.stop if self.server
    self.thread.kill if self.thread
    self.server = nil
    super
  end

  #
  # The MSGRPC instance.
  #
  attr_accessor :server
  attr_accessor :thread
  attr_accessor :users
  attr_accessor :tokens

end

end

